配置管理
最佳实践思想
- 区分必选值与可选择
- 配置文件与选项解耦
- 避免复杂
- 简单化, 除了必选的值, 默认值应该是科学的, 合理的, 最佳实践的值
- 防御编程, 防止其他人乱改和运行时修改配置, 如果用户手一抖, 一秒钟填写成1分钟, 对不合理的配置直接panic
- 配置版本和应用对齐, 回滚应用时, 应用和配置文件应该一一对应, 一起回滚, 在配置中心或者k8s配置
最佳实践
proto + 配置语言(json/yaml/toml)
proto可以进行高亮 yaml编写配置就可以与proto进行解耦
演进
函数配置
防止在运行时修改DailOption配置
优点:
- 告诉你可选和必选值
- 函数内方便使用默认值
扩展:
如果要扩展, 必须新增函数, 例如
DailDatabase等才可以扩展
type DailOption struct {
// dailOption, 小写, 意味着没有任何人有修改里面 的值
f func(*dailOption)
}
func Dial(network, address string, options ...DailOption) (Conn, error){
// 默认值
do := dailOption {
dial: net.Dial,
}
// 如果没有传递options, 也不会造成影响
for _, option := range options {
option.f(&do)
}
}
或者:
type DailOption func(*dailOption)
func Dial(network, address string, options ...DailOption) (Conn, error){
do := dailOption {
dial: net.Dial,
}
for _, option := range options {
option(&do)
}
}
函数配置, 包含返回值
用于单元测试等, 需要切换参数配置时 改之前与改之后
type option func(f *Foo) option
func Verbosity(v int) option {
return func(f *Foo) option {
prev := f.verbostiy
f.verbostiy = v
return Verbosity(prev)
}
}
func DoSomethingVerbosity(foo *Foo, verbosity int) {
prev := foo.Option(pkg.Verbosity(verbostiy))
defer foo.Option(prev)
}
包含interface的函数配置
type GreeterClient interface {
SayHello(ctx context.Context, in *HelloReq, opts ...grpc.CallOption) (*SayHelloReply, error)
}
type CallOption interface {
before(*callInfo) error
after(*callInfo)
}
// EmptyCallOption 不改变 CallCallOption
type EmptyCallOption struct{}
// 对原有的grpc.CallOption进行扩展
type TimeoutCallOption struct {
grpc.EmptyCallOption
Timeout time.Duration
}